Deploy dwd-api-fastapi on the server (Docker)
Copy-paste runbook for msi-laptop-3. Goal: container listening on 127.0.0.1:8001, health check passing.
Full stack (FastAPI + MCP + Copilot): use [hydrotrek-dwd-suite/docker] — compose at /etc/dwd-stack/docker-compose.yml. This runbook covers FastAPI-only bootstrap or individual service clones under /opt/apis/.
Run as gqc over SSH unless noted. Use sudo where shown.
Before you start
- Docker installed (08-docker-install-and-users.md)
-
gqcin groupsapisvcanddocker(re-login afterusermod) - Git deploy key for
gqc/dwd-api-fastapi(07-code-management-and-git.md) - Dockerfile committed and pushed to GitHub (server clone must include it)
From your Windows workstation, if not pushed yet:
cd "c:\jacob\admin\GQC Computers\MSI Laptop 3\repos\dwd-api-fastapi"
git add Dockerfile .dockerignore DOCKER.md
git commit -m "Add Docker support for on-prem deployment"
git push
Step 0 — Verify prerequisites
docker --version
docker compose version
id apisvc
groups # expect: ... apisvc ... docker ...
Step 1 — Clone or update source
API=dwd-api-fastapi
GITHUB_ORG=gqc
GITHUB_REPO=dwd-api-fastapi
# Skip clone if already present — use git pull instead
if [ ! -d /opt/apis/${API}/.git ]; then
git clone git@github.com-${API}:${GITHUB_ORG}/${GITHUB_REPO}.git \
/opt/apis/${API}
fi
cd /opt/apis/${API}
git pull
sudo chown -R apisvc:apisvc /opt/apis/${API}
sudo chmod -R g+rwX /opt/apis/${API}
# Must exist before build:
test -f /opt/apis/${API}/Dockerfile && echo "Dockerfile OK" || echo "MISSING Dockerfile — push to GitHub and git pull"
Step 2 — Host config directories
API=dwd-api-fastapi
sudo mkdir -p /etc/${API}
sudo chown root:apisvc /etc/${API}
sudo chmod 750 /etc/${API}
Step 3 — Secrets env file
API=dwd-api-fastapi
sudo cp /opt/apis/${API}/.env.example /etc/${API}/${API}.env
sudo chmod 640 /etc/${API}/${API}.env
sudo chown root:apisvc /etc/${API}/${API}.env
sudo nano /etc/${API}/${API}.env
Minimum for /health and basic operation: set DWD_API_BASE_URL to your ASP.NET v2 root (must end with /api/):
DWD_API_BASE_URL=https://your-aspnet-host.example.com/api/
Optional: OPENAI_API_KEY if you need POST /agent.
Step 4 — Production compose file
Standard pattern for full stack: hydrotrek-dwd-suite/docker/docker-compose.prod.yml → /etc/dwd-stack/docker-compose.yml.
For FastAPI-only interim deploy, extract the dwd-api-fastapi service block from that file into /etc/dwd-api-fastapi/docker-compose.yml, or run the full stack compose.
After cloning or updating hydrotrek-dwd-suite:
sudo mkdir -p /etc/dwd-stack
sudo chown root:apisvc /etc/dwd-stack
sudo chmod 750 /etc/dwd-stack
sudo cp /opt/apis/hydrotrek-dwd-suite/docker/docker-compose.prod.yml /etc/dwd-stack/docker-compose.yml
sudo chmod 640 /etc/dwd-stack/docker-compose.yml
grep -E 'context:|env_file:|127.0.0.1' /etc/dwd-stack/docker-compose.yml
If the suite repo is not on the server yet, use templates/docker/hydrotrek-dwd-suite/docker-compose.prod.yml.
Stack orchestration lives in hydrotrek-dwd-suite only — not in individual API repos.
Step 5 — Build and start
First build may take several minutes (pip installs inside the image).
API=dwd-api-fastapi
cd /etc/${API}
sudo docker compose build
sudo docker compose up -d
sudo docker compose ps
Step 6 — Verify
curl -s http://127.0.0.1:8001/health
curl -s http://127.0.0.1:8001/ | head
Expected health JSON:
{"status":"ok","agent":{"enabled":false,...}}
Confirm binding is localhost only:
sudo ss -tlnp | grep 8001
# should show 127.0.0.1:8001
Logs:
cd /etc/dwd-api-fastapi
sudo docker compose logs -f --tail=50
Step 7 — systemd (start on boot)
Optional but recommended:
API=dwd-api-fastapi
sudo tee /etc/systemd/system/${API}.service > /dev/null << EOF
[Unit]
Description=${API} (Docker)
Documentation=file:///opt/apis/${API}/README.md
After=docker.service network-online.target
Requires=docker.service
Wants=network-online.target
[Service]
Type=oneshot
RemainAfterExit=yes
WorkingDirectory=/etc/${API}
ExecStart=/usr/bin/docker compose -f /etc/${API}/docker-compose.yml up -d --remove-orphans
ExecStop=/usr/bin/docker compose -f /etc/${API}/docker-compose.yml down
ExecReload=/usr/bin/docker compose -f /etc/${API}/docker-compose.yml up -d --remove-orphans
[Install]
WantedBy=multi-user.target
EOF
sudo systemctl daemon-reload
sudo systemctl enable ${API}
sudo systemctl start ${API}
sudo systemctl status ${API} --no-pager
Routine updates (after git push)
API=dwd-api-fastapi
cd /opt/apis/${API}
git pull
sudo chown -R apisvc:apisvc /opt/apis/${API}
cd /etc/${API}
sudo docker compose build
sudo docker compose up -d
curl -s http://127.0.0.1:8001/health
Troubleshooting
| Symptom | Action |
|---|---|
MISSING Dockerfile | Push Docker files from workstation; git pull on server |
| Build fails on pip | Read build output; check network from server |
| Container exits | sudo docker compose logs |
curl connection refused | sudo docker compose ps; rebuild and up |
| Permission denied on git pull | Confirm groups includes apisvc |
| Port 8001 in use | sudo ss -tlnp \| grep 8001 |
Restart from scratch:
cd /etc/dwd-api-fastapi
sudo docker compose down
sudo docker compose build --no-cache
sudo docker compose up -d
What comes next (not in this doc)
- Nginx LAN HTTP — 11-nginx-lan-setup.md
- SSL on Nginx (443) — uncomment block in LAN config when certs ready
- DNS subdomain → server Ethernet IP (server room)
- UFW — SSH on Wi‑Fi only; 80/443 on Ethernet — 09-wifi-and-ssh-network-setup.md
Checklist
-
git pull— Dockerfile present -
/etc/dwd-api-fastapi/dwd-api-fastapi.env—DWD_API_BASE_URLset -
/etc/dwd-api-fastapi/docker-compose.ymlin place -
docker compose up -d— container running -
curl http://127.0.0.1:8001/health→"status":"ok" -
127.0.0.1:8001only (not0.0.0.0:8001) - systemd unit enabled (optional)